package com.thirtydays.frame.base

import android.annotation.SuppressLint
import android.graphics.Color
import android.view.Gravity
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.alibaba.sdk.android.oss.callback.OSSProgressCallback
import com.alibaba.sdk.android.oss.model.PutObjectRequest
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.NetworkUtils
import com.blankj.utilcode.util.ToastUtils
import com.luck.picture.lib.utils.ToastUtils.showToast
import com.thirtydays.frame.R
import com.thirtydays.frame.base.bean.BaseBean
import com.thirtydays.frame.base.bean.BaseShowBean
import com.thirtydays.frame.base.bean.UpdataFile
import com.thirtydays.frame.base.http.ApiService
import com.thirtydays.frame.base.http.HttpManager
import com.thirtydays.frame.base.http.error.ExceptionHandle
import com.thirtydays.frame.base.http.error.LoginException
import com.thirtydays.frame.data.DataManager
import com.thirtydays.frame.util.OSSUtils
import com.thirtydays.frame.util.StringUtils
import com.thirtydays.frame.util.Upload
import com.thirtydays.frame.util.ext.SingleLiveData
import com.thirtydays.frame.util.ext.getCompatString
import com.thirtydays.frame.util.ext.isNotNull
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import okhttp3.ResponseBody

/**
 * @创建者：小垚
 * @时间：2021/7/2212:27
 * @描述：
 */
open class BaseViewModel : ViewModel() {
    var mIsShowStatus = SingleLiveData<BaseShowBean>()

    var success = SingleLiveData<String?>()

    open val api by lazy { HttpManager.api }

    open fun getHttpApi(baseUrl: String): ApiService {
        return HttpManager.getHttp(baseUrl)
    }


    val userData = SingleLiveData<String>()

    private fun showLoading(tip: String) {
        mIsShowStatus.setValue(BaseShowBean(0, tip))
    }

    private fun showContent() {
        mIsShowStatus.setValue(BaseShowBean(1))
    }

    private fun showError() {
        mIsShowStatus.setValue(BaseShowBean(2))
    }

    private fun hideLoading() {
        mIsShowStatus.setValue(BaseShowBean(3))
    }

    private fun goToLogin() {
        mIsShowStatus.setValue(BaseShowBean(4))
    }

    /**
     * 请求接口，可定制是否显示loading和错误提示
     * 请求接口方法，T表示data实体泛型，调用时可将data对应的bean传入即可
     */
    @SuppressLint("MissingPermission")
    fun <T> launch(
        liveData: MutableLiveData<T>,
        isShowLoading: Boolean = true,
        loadingTip: String = getCompatString(R.string.loading_tip),
        isShowError: Boolean = false,
        isShowToast: Boolean = true,
        onError: (String, String) -> Unit = { _, _ -> },
        block: suspend CoroutineScope.() -> BaseBean<T>,
    ) {
        if (!NetworkUtils.isConnected() && isShowError) {
            showError()
            onError("", "")
            return
        }

        viewModelScope.launch {
            flow { emit(block()) }.flowOn(Dispatchers.IO).onStart {
                if (isShowLoading) {
                    showLoading(loadingTip)
                }
            }.catch { e: Throwable ->
                LogUtils.e("请求异常>>" + e.message)
                if (isShowToast) {
                    showToast(ExceptionHandle.handleException(e))
                }
                if (e is LoginException) {
                    goToLogin()
                } else {
                    if (isShowError) {
                        showError()
                    }
                }
                onError("", ExceptionHandle.handleException(e))
            }.onCompletion {
                if (isShowLoading) {
                    hideLoading()
                }
            }.flowOn(Dispatchers.Main).collect {
                if (it.resultStatus) { //请求成功
                    showContent()
                    liveData.value = it.resultData
                } else {
                    LogUtils.e("请求错误>>${it.errorMessage}")
                    if (isShowToast) {
                        if (it.errorMessage.isNotNull()) {
                            showToast(it.errorMessage)
                        }
                    }
                    if (isShowError) {
                        showError()
                    }
                    onError(it.errorCode, it.errorMessage)
                }
            }
        }
    }

    /**
     * 请求接口，可定制是否显示loading和错误提示
     * 请求接口方法，T表示data实体泛型，调用时可将data对应的bean传入即可
     */
    fun <T> launchFunction(
        isShowLoading: Boolean = true,
        loadingTip: String = getCompatString(R.string.loading_tip),
        isShowError: Boolean = false,
        isShowToast: Boolean = true,
        onError: (String, String) -> Unit = { _, _ -> },
        function: (T) -> Unit,
        block: suspend CoroutineScope.() -> BaseBean<T>,
    ) {
        if (!NetworkUtils.isConnected()) {
            if (isShowError) {
                showError()
            }
            onError("", "")
            return
        }
        viewModelScope.launch {
            flow { emit(block()) }.flowOn(Dispatchers.IO).onStart {
                if (isShowLoading) {
                    showLoading(loadingTip)
                }
            }.catch { e: Throwable ->
                LogUtils.e("请求异常>>" + e.message)
                if (isShowToast) {
                    showToast(ExceptionHandle.handleException(e))
                }
                if (e is LoginException) {
                    goToLogin()
                } else {
                    if (isShowError) {
                        showError()
                    }
                }
                onError("", ExceptionHandle.handleException(e))
            }.onCompletion {
                if (isShowLoading) {
                    hideLoading()
                }
            }.flowOn(Dispatchers.Main).collect {
                if (it.resultStatus) { //请求成功
                    showContent()
                    function(it.resultData)
                } else {
                    LogUtils.e("请求错误>>${it.errorMessage}")
                    if (isShowToast) {
                        if (it.errorMessage.isNotNull()) {
                            showToast(it.errorMessage)
                        }
                    }
                    if (isShowError) {
                        showError()
                    }
                    onError(it.errorCode, if (it.errorMessage.isNullOrEmpty()) "" else it.errorMessage)
                }
            }
        }
    }


    /**
     * 下载文件
     */
    @SuppressLint("MissingPermission")
    var file = SingleLiveData<ResponseBody?>()
    fun downLaunch(url: String, liveData: MutableLiveData<ResponseBody>, isShowLoading: Boolean = true, isShowError: Boolean = false) {
        if (!NetworkUtils.isConnected() && isShowError) {
            showError()
            return
        }
        viewModelScope.launch {
            flow { emit(api.downFile(url)) }.flowOn(Dispatchers.IO).onStart {
                if (isShowLoading) {
                    showLoading(getCompatString(R.string.loading_tip))
                }
            }.catch { e: Throwable ->
                LogUtils.e("请求异常>>" + e.message)

                showToast(ExceptionHandle.handleException(e))
                if (e is LoginException) {
                    goToLogin()
                } else {
                    if (isShowError) {
                        showError()
                    }
                }
            }.onCompletion {
                if (isShowLoading) {
                    hideLoading()
                }
            }.flowOn(Dispatchers.Main).collect {
                liveData.value = it
            }
        }
    }


    /**
     * 需要一对一对应并发上传图片
     */
    @SuppressLint("MissingPermission")
    fun launchMapFile(files: MutableMap<String, UpdataFile>,
                      liveData: MutableLiveData<MutableList<MutableMap<String, String>>>,
                      isShowLoading: Boolean = true,
                      isShowError: Boolean = false,
                      progressCallback: OSSProgressCallback<PutObjectRequest>? = null) {
        if (!NetworkUtils.isConnected() && isShowError) {
            showError()
            return
        }

        viewModelScope.launch {
            flow { emit(api.getOSS()) }.flowOn(Dispatchers.IO).onStart {
                if (isShowLoading) {
                    showLoading(getCompatString(R.string.loading_tip))
                }
            }.catch { e: Throwable ->
                LogUtils.e("请求异常>>" + e.message)
                showToast(ExceptionHandle.handleException(e))
                if (isShowError) {
                    showError()
                }
            }.onCompletion {
                if (isShowLoading) {
                    hideLoading()
                }
            }.map {
                return@map if (it.resultStatus) { //请求成功
                    asyncMapUpdateFile(files, it.resultData, progressCallback)
                } else {
                    LogUtils.e("请求错误>>${it.errorMessage}")

                    showToast("请求错误>>${it.errorMessage}")
                    if (isShowError) {
                        showError()
                    }
                    mutableListOf<MutableMap<String, String>>()
                }
            }.flowOn(Dispatchers.Main).collect {
                hideLoading()
                liveData.value = it
            }
        }
    }

    /**
     * 无需一对一对应并发上传图片
     */
    @SuppressLint("MissingPermission")
    fun launchListFile(files: MutableList<UpdataFile>,
                       liveData: MutableLiveData<MutableList<String>>,
                       isShowLoading: Boolean = true,
                       isShowError: Boolean = false,
                       progressCallback: OSSProgressCallback<PutObjectRequest>? = null) {
        if (!NetworkUtils.isConnected() && isShowError) {
            showError()
            return
        }

        viewModelScope.launch {
            flow { emit(api.getOSS()) }.flowOn(Dispatchers.IO).onStart {
                if (isShowLoading) {
                    showLoading(getCompatString(R.string.loading_tip))
                }
            }.catch { e: Throwable ->
                LogUtils.e("请求异常>>" + e.message)
                showToast(ExceptionHandle.handleException(e))
                if (isShowError) {
                    showError()
                }
            }.onCompletion {
                if (isShowLoading) {
                    hideLoading()
                }
            }.map {
                return@map if (it.resultStatus) { //请求成功
                    asyncListUpdateFile(files, it.resultData, progressCallback)
                } else {
                    LogUtils.e("请求错误>>${it.errorMessage}")

                    showToast("请求错误>>${it.errorMessage}")
                    if (isShowError) {
                        showError()
                    }
                    mutableListOf()
                }
            }.flowOn(Dispatchers.Main).collect {
                hideLoading()
                liveData.value = it
            }
        }
    }


    /**
     * 并发上传文件oss
     */
    private suspend fun asyncMapUpdateFile(files: MutableMap<String, UpdataFile>,
                                           upload: Upload,
                                           progressCallback: OSSProgressCallback<PutObjectRequest>?): MutableList<MutableMap<String, String>> {

        val asyncList = mutableListOf<MutableMap<String, String>>()

        withContext(Dispatchers.IO) {
            files.forEach {
                val async = async {
                    sendAsyncMapFile(it.key, it.value, upload, progressCallback)
                }
                asyncList.add(async.await())
            }
        }
        return asyncList
    }


    /**
     * 并发上传文件oss
     */
    private suspend fun asyncListUpdateFile(files: MutableList<UpdataFile>,
                                            upload: Upload,
                                            progressCallback: OSSProgressCallback<PutObjectRequest>?): MutableList<String> {

        val asyncList = mutableListOf<String>()

        withContext(Dispatchers.IO) {
            files.forEach {
                val async = async {
                    sendAsyncListFile(it, upload, progressCallback)
                }
                asyncList.add(async.await())
            }
        }
        return asyncList
    }


    /**
     * 并发
     */
    private fun sendAsyncMapFile(key: String,
                                 updateFile: UpdataFile,
                                 upload: Upload,
                                 progressCallback: OSSProgressCallback<PutObjectRequest>?): MutableMap<String, String> {
        val substring = updateFile.filePath.substring(
            updateFile.filePath.lastIndexOf("."), updateFile.filePath.length)
        val fileName = "${StringUtils.getRandomString(16)}${substring}"

        val urlmap = mutableMapOf<String, String>()

        val bean = OSSUtils.INSTANCE.uploadFile(upload, updateFile.filePath, fileName, progressCallback)
        if (bean.isSuccess) {
            urlmap[key] = bean.url
        } else {
            urlmap[key] = ""
        }
        return urlmap
    }


    /**
     * 并发
     */
    private fun sendAsyncListFile(updateFile: UpdataFile, upload: Upload, progressCallback: OSSProgressCallback<PutObjectRequest>?): String {
        val substring = updateFile.filePath.substring(
            updateFile.filePath.lastIndexOf("."), updateFile.filePath.length)
        val fileName = "${StringUtils.getRandomString(16)}${substring}"

        val bean = OSSUtils.INSTANCE.uploadFile(upload, updateFile.filePath, fileName, progressCallback)
        return if (bean.isSuccess) {
            bean.url
        } else {
            ""
        }
    }


    private fun showToast(message: String) {
        ToastUtils.getDefaultMaker()
            .setBgResource(R.drawable.trtcliveroom_message_background)
            .setTextColor(Color.WHITE)
            .setGravity(Gravity.CENTER, 0, 0)
            .setMode(ToastUtils.MODE.DARK)
            .setDurationIsLong(false)
            .show(message)
    }

}